using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using SVNClean.Modules;
using SVNClean.Properties;
using Keyrox.Shared.Controls;

namespace SVNClean.Windows {
    public partial class frm_Clean : DevExpress.XtraEditors.XtraForm {
        /// <summary>
        /// Initializes a new instance of the <see cref="frm_Clean"/> class.
        /// </summary>
        public frm_Clean() {
            InitializeComponent();
            if (defaultLookAndFeel1.LookAndFeel.SkinName != AppConfiguration.Current.DefaultSkin) {
                DevExpress.LookAndFeel.UserLookAndFeel.Default.SetSkinStyle(AppConfiguration.Current.DefaultSkin);
                this.defaultLookAndFeel1.LookAndFeel.SetSkinStyle(AppConfiguration.Current.DefaultSkin);
                this.Refresh(); this.Update();
            }

            TMIncreasePosition = new Timer();
            TMIncreasePosition.Interval = 300;
            TMIncreasePosition.Tick += TMIncreasePosition_Tick;

            TMUpdateControls = new Timer();
            TMUpdateControls.Interval = 100;
            TMUpdateControls.Tick += TMUpdateControls_Tick;

            ActualAction = string.Empty;
            ActualDirectory = string.Empty;
            ActualFile = string.Empty;
        }

        #region "[rgn] Formulary Properties "
        public DirectoryInfo DirectoryToClean { get; set; }
        public List<DirectoryInfo> SvnDirectories { get; set; }
        public List<FileInfo> SvnFiles { get; set; }
        public int SVNReferences { get; set; }
        public delegate void CleanActions();
        public int ProgressPosition { get; set; }
        public int ProgressLimit { get; set; }
        public string ActualAction { get; set; }
        public string ActualDirectory { get; set; }
        public string ActualFile { get; set; }
        public Timer TMIncreasePosition { get; set; }
        public Timer TMUpdateControls { get; set; }
        public OperationLog Log { get; set; }
        #endregion

        /// <summary>
        /// Handles the Load event of the frm_Clean control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void frm_Clean_Load(object sender, EventArgs e) {
            ckClose.Checked = AppConfiguration.Current.CloseAfterFinish;
            Log = new OperationLog();
            TMUpdateControls.Start();
            MethodCall.ExecuteSafeThreadIn(new Callback(delegate() { Clean(); }), 1000);
        }

        /// <summary>
        /// Cleans this instance.
        /// </summary>
        public void Clean() {
            ActualAction = Resources.AnalyzingStructure;
            new CleanActions(delegate() { BeginCleanActions(); }).BeginInvoke(null, null);
        }

        /// <summary>
        /// Begins the clean actions.
        /// </summary>
        private void BeginCleanActions() {
            try {
                //Analyze.
                ProgressLimit = 100;
                ProgressPosition = 0;

                this.Invoke(new Callback(delegate() {
                    TMIncreasePosition.Start();
                }));

                ParseSvnFilesAndDirectories();
                Log.TotalSvnReferences = SVNReferences;
                Log.TotalRootFiles = DirectoryToClean.GetDirectories("*", SearchOption.AllDirectories).Length +
                    DirectoryToClean.GetFiles("*", SearchOption.AllDirectories).Length;

                string strRef = SVNReferences.ToString().Length > 1 ? SVNReferences.ToString() : "0" + SVNReferences.ToString();

                this.Invoke(new Callback(delegate() {
                    groupControl1.Text = string.Format(Resources.SVNReferences, strRef);
                    groupControl1.AppearanceCaption.ForeColor = System.Drawing.Color.White;
                    TMIncreasePosition.Stop();
                }));

                //Backup.
                if (AppConfiguration.Current.CreateBackup) {
                    ActualAction = Resources.CreatingBackup;
                    PerformDirectoryBackup();
                }

                //Cleaner.
                ActualAction = Resources.Cleaning;
                ProgressLimit = SVNReferences + 10;
                ProgressPosition = 0;
                RemoveSVNDirectories();

                //Save Log.
                if (AppConfiguration.Current.SaveOperationLog) {
                    Log.RootDirectory = DirectoryToClean;
                    Log.SaveLogFile();

                    if (AppConfiguration.Current.OpenLogAfterClean) {
                        var file = new FileInfo(DirectoryToClean.FullName + Resources.LogFilePath);
                        if (file.Exists) System.Diagnostics.Process.Start(file.FullName);
                    }
                }

                //Finish Actions.
                if (AppConfiguration.Current.SaveLastDirectory) {
                    AppConfiguration.Current.LastCleanedDirectory = DirectoryToClean.FullName;
                    AppConfiguration.Current.SaveData();
                }

                ActualAction = Resources.CleanComplete;
                ActualDirectory = " ";
                ActualFile = " ";
                ProgressLimit = 100;
                ProgressPosition = 100;

                System.Threading.Thread.Sleep(1000);

                this.Invoke(new Callback(delegate() {
                    if (AppConfiguration.Current.CloseAfterFinish) {
                        Close();
                        return;
                    }
                    simpleButton1.Image = Resources.next;
                    simpleButton1.Text = Resources.Close;
                }));
            }
            catch (System.Threading.ThreadAbortException) { /* Main Thread Aborted by Form Close Event! */ }
            catch (Exception ex) { Debugger.Break(); MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Close(); }
        }

        #region "[rgn] Control Events "
        private void TMUpdateControls_Tick(object sender, EventArgs e) {
            if (progressBarControl1.Position != ProgressPosition)
                progressBarControl1.Position = ProgressPosition;

            if (progressBarControl1.Properties.Maximum != ProgressLimit)
                progressBarControl1.Properties.Maximum = ProgressLimit;

            if (lblAction.Text != ActualAction)
                lblAction.Text = ActualAction.Replace(" ", "") != string.Empty ? ActualAction : " ...";

            if (lblDirectories.Text != ActualDirectory)
                lblDirectories.Text = ActualDirectory.Replace(" ","") != string.Empty ? ActualDirectory : " ...";

            if (lblFile.Text != ActualFile)
                lblFile.Text = ActualFile.Replace(" ", "") != string.Empty ? ActualFile : " ...";
        }
        private void TMIncreasePosition_Tick(object sender, EventArgs e) {
            ProgressPosition++;
        }
        private void ckClose_CheckedChanged(object sender, EventArgs e) {
            AppConfiguration.Current.CloseAfterFinish = ckClose.Checked;
            AppConfiguration.Current.SaveData();
        }
        private void simpleButton1_Click(object sender, EventArgs e) {
            Close();
        }
        private void frm_Clean_FormClosing(object sender, FormClosingEventArgs e) {
        }
        #endregion

        /// <summary>
        /// Performs the directory backup.
        /// </summary>
        private void PerformDirectoryBackup() {
            var target = new DirectoryInfo(Path.Combine(DirectoryToClean.Parent.FullName, DirectoryToClean.Name + " [Backup]"));
            if (target.Exists) {

                if (AppConfiguration.Current.DeleteOldBackup) {
                    ProgressLimit = target.GetFiles("*", SearchOption.AllDirectories).Count() +
                        target.GetDirectories("*", SearchOption.AllDirectories).Count() + 20;
                    ProgressPosition = 0;
                    ActualAction = Resources.DeleteBackup;
                    DeleteAll(target);
                }
                else {
                    var result = MessageBox.Show(string.Concat(
                        Resources.OldBackupFound, "\n",
                        Resources.DeleteBackupQuestion), "Warning",
                        MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                    switch (result) {
                        case DialogResult.Cancel:
                            this.Close();
                            return;
                        case DialogResult.Yes:
                            try {
                                ProgressLimit = target.GetFiles("*", SearchOption.AllDirectories).Count() +
                                    target.GetDirectories("*", SearchOption.AllDirectories).Count() + 20;
                                ProgressPosition = 0;
                                ActualAction = Resources.DeleteBackup;
                                DeleteAll(target);
                            }
                            catch (IOException ex) {
                                if (MessageBox.Show(ex.Message, "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error)
                                    == DialogResult.Cancel) {
                                    Close();
                                }
                            }
                            break;
                        case DialogResult.No:
                            target = new DirectoryInfo(Path.Combine(DirectoryToClean.Parent.FullName, DirectoryToClean.Name + " [Backup] " + DateTime.Now.ToString("dd-MM-yyyy hh.mm.ss")));
                            break;
                    }
                }
            }
            ActualAction = Resources.CreatingBackup;
            ProgressPosition = 0;
            ProgressLimit =
                DirectoryToClean.GetDirectories("*", SearchOption.AllDirectories).Length +
                DirectoryToClean.GetFiles("*", SearchOption.AllDirectories).Length + 20;
            CopyTo(DirectoryToClean, target);
        }

        /// <summary>
        /// Removes the SVN directories.
        /// </summary>
        private void RemoveSVNDirectories() {
            var dirs = SvnDirectories;
            dirs.Reverse();
            foreach (var dir in dirs) {
                DeleteAll(dir);
            }
        }

        /// <summary>
        /// Parses the SVN files and directories.
        /// </summary>
        private void ParseSvnFilesAndDirectories() {
            SvnDirectories = new List<DirectoryInfo>();
            SVNReferences = 0;
            foreach (string svn in SvnDirectoryNames.Names) {
                SvnDirectories.AddRange(DirectoryToClean.GetDirectories(svn, SearchOption.AllDirectories));
            }
            SvnFiles = new List<FileInfo>();
            foreach (var dir in SvnDirectories) {
                SVNReferences += dir.GetDirectories("*", SearchOption.AllDirectories).Length;
                SvnFiles.AddRange(dir.GetFiles("*", SearchOption.AllDirectories));
            }
            SVNReferences += (SvnDirectories.Count + SvnFiles.Count);
        }

        /// <summary>
        /// Copies to.
        /// </summary>
        /// <param name="sourceDir">The source dir.</param>
        /// <param name="targetDir">The target dir.</param>
        private void CopyTo(DirectoryInfo sourceDir, DirectoryInfo targetDir) {
            if (!Directory.Exists(targetDir.FullName)) {
                Directory.CreateDirectory(targetDir.FullName);
            }

            foreach (FileInfo fileInfo in sourceDir.GetFiles()) {
                ShowDirectoryInfoText(fileInfo.FullName);
                fileInfo.CopyTo(Path.Combine(targetDir.ToString(), fileInfo.Name), true);
                ProgressPosition++;
            }

            foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories()) {
                DirectoryInfo targetSubDir = targetDir.CreateSubdirectory(sourceSubDir.Name);
                CopyTo(sourceSubDir, targetSubDir);
            }
        }

        /// <summary>
        /// Deletes all.
        /// </summary>
        /// <param name="sourceDir">The source dir.</param>
        private void DeleteAll(DirectoryInfo sourceDir) {
            var subdirs = sourceDir.GetDirectories();
            DeleteAllFiles(sourceDir);
            subdirs.Reverse();
            foreach (var dir in subdirs) {
                if (dir.GetDirectories().Count() > 0) {
                    DeleteAll(dir);
                }
                else {
                    dir.Attributes = FileAttributes.Directory;
                    ShowDirectoryInfoText(dir.FullName);
                    dir.Delete();
                    ProgressPosition++;
                }
            }
            ShowDirectoryInfoText(sourceDir.FullName);
            sourceDir.Delete();
            ProgressPosition++;
        }

        /// <summary>
        /// Deletes all files.
        /// </summary>
        /// <param name="dir">The dir.</param>
        private void DeleteAllFiles(DirectoryInfo dir) {
            var files = dir.GetFiles("*", SearchOption.AllDirectories);
            foreach (var file in files) {
                file.Attributes = FileAttributes.Archive;
                ShowDirectoryInfoText(file.FullName);
                file.Delete();
                ProgressPosition++;
            }
        }

        /// <summary>
        /// Shows the directory info text.
        /// </summary>
        /// <param name="path">The path.</param>
        private void ShowDirectoryInfoText(string path) {
            ActualDirectory = Extensions.GetShortPathName(Path.GetDirectoryName(path));
            ActualFile = Path.GetFileName(path);
            Log.AddOperation(path, ActualAction);
        }

    }
}